// 引用gulp模块
const gulp = require('gulp');
// html 压缩、合并
const htmlmin = require('gulp-htmlmin');
const fileinclude = require('gulp-file-include');
// less转化css、css压缩
var LessAutoprefix = require('less-plugin-autoprefix');
var autoprefix = new LessAutoprefix({ browsers: ['last 2 versions', 'ie 6-8', 'ie 11', 'Firefox > 20'] });
const less = require('gulp-less');
const csso = require('gulp-csso');
// js转化、压缩、重命名、合并
const babel = require('gulp-babel');
const uglify = require('gulp-uglify');
const browserify = require('gulp-browserify');
const rename = require('gulp-rename');
const concat = require('gulp-concat');
// 编译前删除
const del = require('del');
// 图片压缩相关
const imagemin = require('gulp-imagemin'); //压缩图片文件
// const pngquant = require('imagemin-pngquant'); //png图片压缩插件
const cache = require('gulp-cache'); //压缩图片可能会占用较长时间，使用 gulp-cache 插件可以减少重复压缩。


// 服务监听相关
const watch = require('gulp-watch');
const path = require('path');
var browserSync = require("browser-sync").create();//打开浏览器
// 本地开发代理跨域请求用的插件
const proxyMiddleware = require('http-proxy-middleware').createProxyMiddleware;

/**
 * 打包前先清理原来的已经打包的内容
 */
gulp.task('clean', async () => {
  del.sync('dist/**/*');
});

/**
 * html 任务
 * 1. html 文件中代码的压缩
 * 2. 抽取html中公共代码
 * npm install gulp-htmlmin
 * npm install gulp-file-include // 自己手动抽取公共部分到单独文件夹 然后抽取部分用@@include('路径')表示
 */
gulp.task('htmlmin', async () => { // 不加上 async 会报错
  gulp.src(['./src/**/*.html', '!./src/common/**/*.html']) // !取反表示某个目录下的东西不输出
    // 压缩html代码
    .pipe(fileinclude({         //[fileinclude 可以将拆出来的公共模块打包进页面](https://www.cnblogs.com/nzbin/p/7467546.html)
      prefix: '@@',             //变量前缀 @@include
      // 组件路径为 client\src\common\about.html
      basepath: './src',        // 定义为入口文件夹即可 页面内引入组件，都是组件相对于入口文件路径
      indent: true              //保留文件的缩进
    }))                         // 将抽离的代码引入文件
    .on('error', function (err) { console.log(err.toString()); }) //增加这一行
    // .pipe(htmlmin({
    //   collapseWhitespace: true
    // })) // 压缩html为一行
    .pipe(gulp.dest('dist'));   // 输出到打包目录下

});

/**
 * css任务
 * 1. less语法转换
 * 2. css代码压缩
 * npm install gulp-less // less 转化
 * npm install csso // 压缩css
 * 如何同时选中 .css和 .less， src中传入数组，数组值为字符串路径
 */
gulp.task('cssmin', async () => {
  gulp.src(['./src/css/*.less', '!./src/css/*.css', '!./src/css/?(component).*.*'])
    .pipe(less({
      plugins: [autoprefix]
    })) // 先转化less为css
    .pipe(csso()) // 压缩css文件
    .pipe(gulp.dest('dist/css')); // 输出到打包目录
});

/**
 * JavaScript 任务
 * 1. es6语法转换
 * 2. 代码压缩
 * npm install gulp-babel @babel/core @babel/preset-env //es6语法转换
 * npm install gulp-uglify //代码压缩
 */
gulp.task('jsmin', async () => {
  gulp.src('./src/js/*.js')
    // 语法转换
    .pipe(babel({
      presets: ["@babel/preset-env"]                  // 判断当前代码运行环境，把代码转化成当前环境支持的代码
    }))
    // .pipe(gulp.dest('src/test'))                      // 直接用下一步骤转化会报错，因此先，输出到 test 目录
    .pipe(browserify({ entery: './src/test/*.js' }))  // browserify 包裹一层
    .pipe(gulp.dest('dist/js'))                       // 1）每个js在浏览器能看的
    // .pipe(uglify({
    //   mangle: { toplevel: true },
    // }))                         // 对 js 压缩(只有转换过的代码才可以进行压缩，转换的时候会去掉注释)
    .on('error', function (err) { console.log(err.toString()); }) //增加这一行
    .pipe(rename({
      suffix: '.min'
    })) // 重命名
    .pipe(gulp.dest('dist/js')) // 输出到 dist 目录
    .pipe(concat('build.min.js')) // 打包所有的js到一个文件中取名为build.js
    .pipe(gulp.dest('dist/js')); // 输出到 dist 目录
});

/**
 * 压缩图片
 */
gulp.task('imagesmin', function () {
  return gulp.src('./src/images/*.+(png|jpg|jpeg|gif|svg)')
    .pipe(cache(imagemin({
      interlaced: true,
      progressive: true,
      optimizationLevel: 5,
      plugins: [
        { removeViewBox: true },
        { cleanupIDs: false }
      ]
    }))) //压缩图片文件
    .pipe(gulp.dest('dist/images'));
});

/**
 * 拷贝 lib 文件夹 到压缩目录
 */
gulp.task('copy', async () => {
  // 获取图片文件
  // gulp.src('./src/images/*')
  // 	.pipe(gulp.dest('dist/images')); // 输出文件
  // 获取lib库文件
  gulp.src(['./src/lib/**/*']) // ! 取反 none.js不添加进入dist文件中
    .pipe(gulp.dest('dist/lib')); // 输出库文件
});

/**
 * gulp-watch封装 监听文件变化 npm i gulp-watch --save-dev
 */
gulp.task('watch', async () => {

  w('./src/**/*.html', ['htmlmin']);
  w(['./src/css/*.less', './src/css/*.css', './src/common/**/*.(less|css)'], ['cssmin']);
  w('./src/js/*.js', ['jsmin']);
  w('./src/images/*', ['imagesmin']);

  function w (taskFilePath, task) {
    const watcher = watch(taskFilePath, gulp.series(task));

    watcher.on('error', function (err) {
      console.log(err.toString());
      this.emit("end");
    });

    watcher.on('change', function (filePath, eventHandler) {
      console.log(`File ${filePath} was changed`);
      browserSync.reload();
    });

    watcher.on('add', function (filePath, eventHandler) { console.log(`File ${filePath} was added`); });

    watcher.on('unlink', function (filePath, eventHandler) {
      console.log(`File ${filePath} was removed`);
      const fatherPath = path.dirname(filePath).split('\\').pop();
      // html文件打包 【没】 放入文件夹的时候
      const _fatherPath = path.extname(filePath) === '.html'
        ? 'dist/'
        : 'dist/' + fatherPath + '/';
      // html打包放入文件夹的时候
      // _fatherPath = 'dist/' + fatherPath + '/';
      const filenameExcludeExt = path.basename(filePath).substring(0, path.basename(filePath).indexOf(path.extname(filePath)));
      const fileExt = path.extname(filePath);
      console.log(`${_fatherPath}${filenameExcludeExt}?(.min)${fileExt}`);
      del.sync(`${_fatherPath}${filenameExcludeExt}?(.min)?(${fileExt}|.css)`);
    });
    return watcher;
  }
});

// 定义proxy规则，供下面创建服务使用，以/service/开头的代理到target域名下
const proxy = proxyMiddleware(['/service/'], {
  target: 'http://127.0.0.1:3000',
  changeOrigin: true,
  pathRewrite: {
    '^/api': ''
  },
  logLevel: 'debug'
});


// 静态服务器
gulp.task('browserSync', function () {
  const files = [				//监视的文件类型,
    '**.html',		//"**"是glob的语法,相当于"匹配多个字符,包括/"
    '**.css',
    '**.js'
  ];
  browserSync.init({
    files: files,
    server: {
      baseDir: "./dist",
      index: "index.html",
      middleware: proxy
    },
    port: 4000
  }, function (err, bs) {		//此处添加cb, 以防warning: TypeError args.cb is not a function
    if (err) console.log(err.toString());
  });
});


/**
 * 创建 default任务 整合 gulp 所有任务
 * 一次性打包使用
 */
gulp.task('default', gulp.series('clean', 'htmlmin', 'cssmin', 'jsmin', 'imagesmin', 'copy', async () => {
  console.log('gulp.series finished');
}));


//定义任务  监听index.html 启动webserver
gulp.task('dev', gulp.series('default', 'watch', 'browserSync'));